/*
 * Copyright (c) 2008, Xiong Yingfei, the University of Tokyo
 * All rights reserved.
 */
package ac.jp.u_tokyo.SyncLib.dictionaries;

import java.util.Arrays;

import ac.jp.u_tokyo.SyncLib.Mod;
import ac.jp.u_tokyo.SyncLib.PrimMod;
import ac.jp.u_tokyo.SyncLib.Sync;
import ac.jp.u_tokyo.SyncLib.SyncFactory;
import ac.jp.u_tokyo.SyncLib.SynchronizationFailedException;

public class KeyDictMapCombinator extends MatchingDictMapCombinator
{

	public KeyDictMapCombinator(SyncFactory innerSync,
			KeyFactory[] keyFactories, int nonDictCount)
	{
		super(innerSync, keyFactories, nonDictCount);
	}

	@Override
	protected Mod[] doInvokeResync(Sync newSync, Object[] selectedKeys,
			Mod[] mods, Object[] values) throws SynchronizationFailedException
	{
		Mod[] newmods = toKeyMods(selectedKeys, mods);
		Object[] keyValues = toKeyValues(selectedKeys, values);
		return removeKeyMods(invokeResync(newSync, keyValues, newmods));
	}
	
	@Override
	protected int getNonDictStartIndex()
	{
		return getDictCount() * 2;
	}

	@Override
	public String toString()
	{
		return "KeyDictMapCombinator@" + hashCode();
	}

	private Mod[] toKeyMods(Object[] selectedKeys, Mod[] mods)
	{
		Mod[] newmods = new Mod[getDictCount() * 2 + _nonDictCount];
		for (int i = 0; i < getDictCount(); i++)
		{
			newmods[i] = mods[i];
			assert newmods[i] != null;
		}
		for (int i = getDictCount(); i < getDictCount() * 2; i++)
		{
			newmods[i] = new PrimMod(selectedKeys[i - getDictCount()]);
			assert newmods[i] != null;
		}
		for (int i = getDictCount() * 2; i < _nonDictCount + getDictCount() * 2; i++)
		{
			newmods[i] = mods[i - getDictCount()];
			assert newmods[i] != null;
		}
		return newmods;
	}
	
	private Object[] toKeyValues(Object[] selectedKeys, Object[] values)
	{
		Object[] result = new Object[getDictCount() * 2 + _nonDictCount];
		for (int i = 0; i < getDictCount(); i++)
		{
			result[i] = values[i];
		}
		for (int i = getDictCount(); i < getDictCount() * 2; i++)
		{
			result[i] = selectedKeys[i - getDictCount()];
		}
		for (int i = getDictCount() * 2; i < _nonDictCount + getDictCount() * 2; i++)
		{
			result[i] = values[i - getDictCount()];
		}
		return result;
	}
	
	private Mod[] removeKeyMods(Mod[] mods) {
		Mod[] newmods = new Mod[getDictCount() + _nonDictCount];
		for (int i = 0; i < getDictCount(); i++)
		{
			newmods[i] = mods[i];
			assert newmods[i] != null;
		}
		for (int i = getDictCount() * 2; i < _nonDictCount + getDictCount() * 2; i++)
		{
			newmods[i - getDictCount()] = mods[i];
			assert newmods[i - getDictCount()] != null;
		}
		return newmods;
		
	}


	@Override
	protected Mod[] doInvokeSync(Sync sync, Object[] keys, Mod[] mods)
			throws SynchronizationFailedException
	{
		Mod[] result = invokeSync(sync, toKeyMods(keys, mods));
		return removeKeyMods(result);
	}
	
	

}
